﻿/*
 * FreeSpaceCleaner
 * 
 * 
 * 
 * 
 */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Management;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Microsoft.Win32.SafeHandles;

namespace FreeSpaceCleaner
{
    public class Form1 : Form
    {
        private const int FILE_FLAG_NO_BUFFERING = 0x20000000;
        private const int FILE_FLAG_OVERLAPPED = 0x40000000;
        private readonly byte[] _array = new byte[0x1000000];
        private readonly List<LogicalDisk> _ldCollection = new List<LogicalDisk>();
        private readonly List<HardDrive> _hdCollection = new List<HardDrive>();
        private BackgroundWorker backgroundWorker1;
        private Button button1;
        private Button button2;
        private CheckBox checkBox1;
        private ComboBox comboBox1;
        private ProgressBar progressBar1;

        private string path;
        private Timer timer1;

        public Form1()
        {
            
            InitializeComponent();

        }

        /// <summary>
        /// Event handler to start the worker task
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            var worker = sender as BackgroundWorker;
            
            WriteFileSeq(path, worker);
            if (worker.CancellationPending)
            {
                e.Cancel = true;
            }
        }

        /// <summary>
        /// Event handler to perform when the task is complete
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            button1.Enabled = true;
            button2.Enabled = false;
            timer1.Enabled = false;
            if (e.Cancelled)
            {
                UpdateProgress(sender, null);
                Text = "Canceled!";
            }
            else
            {
                progressBar1.Value = progressBar1.Maximum;
                Text = "Finished!";
            }
        }

        /// <summary>
        /// Event handler to start the Async Task
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            button1.Enabled = false;
            button2.Enabled = true;
            timer1.Enabled = true;
            Text = "Wiping...";
            backgroundWorker1.RunWorkerAsync();
        }

        /// <summary>
        /// Event handler to stop the Async Task
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            backgroundWorker1.CancelAsync();
            
        }

        /// <summary>
        /// Event handler to switch the target drive based on when the combo box changes
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            LogicalDisk disk = _ldCollection[comboBox1.SelectedIndex];
            path = disk.DeviceId + @"\cleaner.dat";
        }
        /// <summary>
        /// kernel32.dll import of CreateFile so we can wipe the free space with the file we've created
        /// </summary>
        /// <param name="lpFileName"></param>
        /// <param name="dwDesiredAccess"></param>
        /// <param name="dwShareMode"></param>
        /// <param name="lpSecurityAttributes"></param>
        /// <param name="dwCreationDisposition"></param>
        /// <param name="dwFlagsAndAttributes"></param>
        /// <param name="hTemplateFile"></param>
        /// <returns></returns>
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern SafeFileHandle CreateFile(string lpFileName, FileAccess dwDesiredAccess,
                                                        FileShare dwShareMode, IntPtr lpSecurityAttributes,
                                                        FileMode dwCreationDisposition, int dwFlagsAndAttributes,
                                                        IntPtr hTemplateFile);


        /// <summary>
        /// Form Loading events
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e)
        {
            var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
            foreach (ManagementObject obj2 in searcher.Get())
            {
                var drive = new HardDrive();
                try
                {
                    drive.Model = obj2["Model"].ToString();
                    drive.DeviceID = obj2["DeviceID"].ToString();
                    drive.Type = obj2["InterfaceType"].ToString();
                    drive.Size = obj2["Size"].ToString();
                    drive.Firmware = obj2["FirmwareRevision"].ToString();
                    _hdCollection.Add(drive);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
                try
                {
                    var searcher2 =
                        new ManagementObjectSearcher("ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + obj2["DeviceID"] +
                                                     "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition");
                    foreach (ManagementObject obj3 in searcher2.Get())
                    {
                        var searcher3 =
                            new ManagementObjectSearcher("ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" +
                                                         obj3["DeviceID"] +
                                                         "'} WHERE AssocClass = Win32_LogicalDiskToPartition");
                        foreach (ManagementObject obj4 in searcher3.Get())
                        {
                            var disk = new LogicalDisk
                                           {
                                               Hdd = drive,
                                               DeviceId = obj4["DeviceID"].ToString()
                                           };
                            _ldCollection.Add(disk);
                        }
                    }
                }
                catch(Exception ex)
                {
                    // if this exception caused us to not have any hard drives in the list, tell the user
                    if(_ldCollection.Count == 0)
                    {
                        MessageBox.Show(ex.ToString());
                    }
                }
            }
            _ldCollection.Sort();
            foreach (LogicalDisk disk in _ldCollection)
            {
                comboBox1.Items.Add(disk.DeviceId + " " + disk.Hdd.Model);
            }
            comboBox1.SelectedIndex = 0;
          
        }

     
        /// <summary>
        /// Event handler to query disk free compared to disk space left to tell the user how complete we are
        /// </summary>
        /// <param name="sender">object sender</param>
        /// <param name="progressChangedEventArgs">progressChangedEventArgs args</param>
        private void UpdateProgress(object sender, ProgressChangedEventArgs progressChangedEventArgs)
        {
            if (_hdCollection.Count == 0)
            {
                return;
            }

            var disk =
                new ManagementObject("win32_logicaldisk.deviceid=\"" + _ldCollection[comboBox1.SelectedIndex].DeviceId +
                                     "\"");
            disk.Get();


            double size = 1;
            double freespace = 1;
            if (double.TryParse(disk["Size"].ToString(), out size) &&
                double.TryParse(disk["FreeSpace"].ToString(), out freespace))
            {
                double val = ((size - freespace)/size)*100;
                progressBar1.Value = (int) val - 1;
            }
            Text = progressBar1.Value + "% Done";
        }

        /// <summary>
        /// Private method to write files to a specified path given a background worker to report progress
        /// </summary>
        /// <param name="path">string File path to write data to</param>
        /// <param name="worker">BackgroundWorker to report progress to</param>
        private void WriteFileSeq(string path, BackgroundWorker worker)
        {
            int num;
            new FileInfo(path).Delete();
            var rand = new Random();

            if (!checkBox1.Checked)
            {
                for (num = 0; num < _array.Length; num++)
                {
                    _array[num] = 0;
                }
            }
            else
            {
                for (num = 0; num < _array.Length; num++)
                {
                    _array[num] = (byte) rand.Next(0, 255);
                }
            }
            SafeFileHandle handle = CreateFile(path, FileAccess.ReadWrite, FileShare.None, IntPtr.Zero,
                                               FileMode.CreateNew, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED,
                                               IntPtr.Zero);
            if (handle.IsInvalid)
            {
                throw new IOException("Could not open file stream.", new Win32Exception());
            }
            var stream = new FileStream(handle, FileAccess.ReadWrite, 0x1000000, true);
            bool flag = true;
            while (flag)
            {
                try
                {
                    if (worker.CancellationPending)
                    {
                        flag = false;
                    }
                    backgroundWorker1.ReportProgress(1);
                    stream.Write(_array, 0, 0x1000000);
                }
                catch
                {
                    flag = false;
                }
            }
            stream.Flush();
            stream.Close();
            new FileInfo(path).Delete();
        }

        #region InitializeComponentCode
        /// <summary>
        /// Create the form controls
        /// This method is created here because this code was decompiled from the original source
        /// Original Author is unknown at time of writing
        /// </summary>
        private void InitializeComponent()
        {

            this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
            this.progressBar1 = new System.Windows.Forms.ProgressBar();
            this.button1 = new System.Windows.Forms.Button();
            this.timer1 = new System.Windows.Forms.Timer();
            this.button2 = new System.Windows.Forms.Button();
            this.checkBox1 = new System.Windows.Forms.CheckBox();
            this.comboBox1 = new System.Windows.Forms.ComboBox();
            this.SuspendLayout();
            // 
            // backgroundWorker1
            // 
            this.backgroundWorker1.WorkerReportsProgress = true;
            this.backgroundWorker1.WorkerSupportsCancellation = true;
            this.backgroundWorker1.DoWork += backgroundWorker1_DoWork;
            this.backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
            this.backgroundWorker1.ProgressChanged += UpdateProgress;
            // 
            // progressBar1
            // 
            this.progressBar1.Location = new System.Drawing.Point(20, 43);
            this.progressBar1.Name = "progressBar1";
            this.progressBar1.Size = new System.Drawing.Size(482, 44);
            this.progressBar1.TabIndex = 0;
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(84, 93);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(140, 44);
            this.button1.TabIndex = 1;
            this.button1.Text = "Clean";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += this.button1_Click;
            // 
            // timer1
            // 
            this.timer1.Enabled = true;
            // 
            // button2
            // 
            this.button2.Enabled = false;
            this.button2.Location = new System.Drawing.Point(291, 93);
            this.button2.Name = "button2";
            this.button2.Size = new System.Drawing.Size(123, 43);
            this.button2.TabIndex = 2;
            this.button2.Text = "Cancel";
            this.button2.UseVisualStyleBackColor = true;
            this.button2.Click += this.button2_Click;
            // 
            // checkBox1
            // 
            this.checkBox1.AutoSize = true;
            this.checkBox1.Location = new System.Drawing.Point(291, 8);
            this.checkBox1.Name = "checkBox1";
            this.checkBox1.Size = new System.Drawing.Size(114, 17);
            this.checkBox1.TabIndex = 3;
            this.checkBox1.Text = "write random bytes";
            this.checkBox1.UseVisualStyleBackColor = true;
            // 
            // comboBox1
            // 
            this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
            this.comboBox1.FormattingEnabled = true;
            this.comboBox1.Location = new System.Drawing.Point(20, 8);
            this.comboBox1.Name = "comboBox1";
            this.comboBox1.Size = new System.Drawing.Size(265, 21);
            this.comboBox1.TabIndex = 4;
            this.comboBox1.SelectedIndexChanged += this.comboBox1_SelectedIndexChanged;
            // 
            // Form1
            // 
            this.Load += this.Form1_Load;
            this.ClientSize = new System.Drawing.Size(514, 149);
            this.Controls.Add(this.comboBox1);
            this.Controls.Add(this.checkBox1);
            this.Controls.Add(this.button2);
            this.Controls.Add(this.button1);
            this.Controls.Add(this.progressBar1);
            this.Name = "Form1";
            this.Text = "AS Cleaner 0.7";
            this.ResumeLayout(false);
            this.PerformLayout();

        }
        #endregion

    }
}